/**
 * 检查IP是否为内网IP
 * @param {string} ip - 待检查的IP地址
 * @returns {boolean} - 是否为内网IP
 */
function isPrivateIp(ip) {
  // 内网IP保留地址范围正则
  const privateIpRegex = [
    // IPv4 私有地址
    /^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, // 10.0.0.0 - 10.255.255.255
    /^172\.(1[6-9]|2\d|3[0-1])\.\d{1,3}\.\d{1,3}$/, // 172.16.0.0 - 172.31.255.255
    /^192\.168\.\d{1,3}\.\d{1,3}$/, // 192.168.0.0 - 192.168.255.255
    /^169\.254\.\d{1,3}\.\d{1,3}$/, // 169.254.0.0 - 169.254.255.255 (APIPA)

    // IPv4 特殊地址
    /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, // 127.0.0.0 - 127.255.255.255 (环回地址)
    /^0\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, // 0.0.0.0 - 0.255.255.255 (当前网络)
    /^100\.(6[4-9]|[7-9]\d|1[0-1]\d|12[0-7])\.\d{1,3}\.\d{1,3}$/, // 100.64.0.0 - 100.127.255.255 (CGNAT)

    // IPv6 私有和特殊地址
    /^::1$/, // IPv6 环回地址
    /^::ffff:((10|127|192\.168|172\.(1[6-9]|2\d|3[0-1]))\.\d{1,3}\.\d{1,3})$/i, // IPv4映射的IPv6私有地址
    /^fc00:/i, // IPv6 唯一本地地址 (ULA) fc00::/7
    /^fd[0-9a-f]{2}:/i, // IPv6 唯一本地地址 fd00::/8
    /^fe80:/i, // IPv6 链路本地地址 fe80::/10
    /^2001:db8:/i, // IPv6 文档地址 2001:db8::/32
    /^2001:0:/i, // IPv6 Teredo 隧道
    /^2002:/i, // IPv6 6to4 隧道
    /^::$/, // IPv6 未指定地址
    /^::$/, // IPv6 压缩格式的未指定地址

    // 多播地址
    /^22[4-9]\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, // 224.0.0.0 - 239.255.255.255
    /^2[3-4]\d\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, // 224.0.0.0 - 239.255.255.255
    /^ff[0-9a-f]{2}:/i, // IPv6 多播地址 ff00::/8

    // 测试网络地址
    /^192\.0\.2\.\d{1,3}$/, // 192.0.2.0/24 (TEST-NET-1)
    /^198\.51\.100\.\d{1,3}$/, // 198.51.100.0/24 (TEST-NET-2)
    /^203\.0\.113\.\d{1,3}$/, // 203.0.113.0/24 (TEST-NET-3)

    // 基准测试地址
    /^198\.18\.\d{1,3}\.\d{1,3}$/, // 198.18.0.0/15 (网络设备基准测试)

    // Carrier-grade NAT
    /^100\.(6[4-9]|[7-9]\d|1[0-1]\d|12[0-7])\.\d{1,3}\.\d{1,3}$/
  ];

  // 测试IP是否匹配任何内网网段
  return privateIpRegex.some((regex) => regex.test(ip));
}

/**
 * 检查IP是否为公网IP
 * @param {string} ip - 待检查的IP地址
 * @returns {boolean} - 是否为公网IP
 */
function isPublicIp(ip) {
  // 先验证IP格式是否合法
  if (!isValidIp(ip)) {
    throw new Error("无效的IP地址");
  }

  // 公网IP = 不是内网IP且不是回环地址
  return !isPrivateIp(ip);
}

/**
 * 验证IP地址格式是否合法
 * @param {string} ip - 待验证的IP地址
 * @returns {boolean} - 是否为合法IP
 */
function isValidIp(ip) {
  // IPv4 格式验证
  const ipv4Regex = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
  if (ipv4Regex.test(ip)) {
    return ip.split(".").every((part) => {
      const num = parseInt(part, 10);
      return num >= 0 && num <= 255; // 每个段必须在0-255之间
    });
  }

  // IPv6 格式简单验证（完整验证较复杂，这里做基础判断）
  const ipv6Regex = /^([0-9a-fA-F:]+)$/;
  return ipv6Regex.test(ip);
}

// // 测试示例
// const testIps = [
//   "114.114.114.114", // 公网IP
//   "192.168.1.1", // 内网IP
//   "10.0.0.1", // 内网IP
//   "172.16.0.1", // 内网IP
//   "127.0.0.1", // 本地回环
//   "8.8.8.8", // 公网IP
//   "::1", // IPv6 本地回环
//   "2001:4860:4860::8888" // IPv6 公网IP
// ];

// testIps.forEach((ip) => {
//   try {
//     console.log(`${ip} => 公网IP: ${isPublicIp(ip)}`);
//   } catch (error) {
//     console.log(`${ip} => ${error.message}`);
//   }
// });

/**
 * @method 获取客户端IP地址
 * @param {string} req 传入请求HttpRequest
 * 客户请求的IP地址存在于request对象当中
 * express框架可以直接通过 req.ip 获取
 */
function getClientIp(req) {
  return (
    req.headers["x-forwarded-for"] ||
    req.ip ||
    req.connection.remoteAddress ||
    req.socket.remoteAddress ||
    req.connection.socket.remoteAddress ||
    ""
  );
}

module.exports = {
  isPublicIp,
  isPrivateIp,
  isValidIp
};
